/*
Copyright (c) [2019年5月1日] [吴超]
[MBT_studio] is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
		 http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
*/
#include "stdafx.h"
#include "PBD核心.h"


//#include "core/CUDA_utils.cuh"
//static cudaStream_t stm;



S_PDB数据::S_PDB数据() {
	m_流体粒子总数 = 0;
	m_飞溅粒子数量 = 0;
	//m_静态粒子总数 = 0;
	//m_步进时间 = 1.0;
	//m_粒子半径 = 1.8;
	m_GPU数据.m_线程块大小 = 1024;

	m_GPU数据.m_cu位置 = nullptr;
	m_GPU数据.m_cu前一帧位置 = nullptr;
	m_GPU数据.m_cu速度 = nullptr;
	m_GPU数据.m_cu加速度 = nullptr;
	m_GPU数据.m_cu移动变化量 = nullptr;
	m_GPU数据.m_cu质量 = nullptr;
	m_GPU数据.m_cu平方范数 = nullptr;



	m_重力 = { 0.0f, -9.8f, 0.0f };
	m_密度0 = 1000.0f;
	m_粘度 = 0.001;

	//m_域单元大小 = 1.0;
	//m_邻接最大粒子数 = 64;
	//cudaStreamCreate(&stm);

	//mIR_密度0 = 1000.0f;
	//m_内核因子 = 8.0 / (M_PI*(m_粒子半径* m_粒子半径* m_粒子半径));
	//m_粒子光滑半径 = 48.0 / (M_PI * (m_粒子半径* m_粒子半径* m_粒子半径));


	m_静态网格空间划分 = f_空间划分_create球形八叉树(64);
}

S_PDB数据::~S_PDB数据() {
	if (m_GPU数据.m_cu位置) {
		/*cudaFree(m_GPU数据.m_cu位置);
		cudaFree(m_GPU数据.m_cu前一帧位置);
		cudaFree(m_GPU数据.m_cu速度);
		cudaFree(m_GPU数据.m_cu加速度);
		cudaFree(m_GPU数据.m_cu移动变化量);
		cudaFree(m_GPU数据.m_cu质量);
		cudaFree(m_GPU数据.m_cu平方范数);
		cudaFree(m_GPU数据.m_cu物理体类型);*/
	}

	//if (m_GPU数据.m_cu刚体起始索引) cudaFree(m_GPU数据.m_cu刚体起始索引);
	//if (m_GPU数据.m_cu刚体粒子数量) cudaFree(m_GPU数据.m_cu刚体粒子数量);
	//if (m_GPU数据.m_cu刚体初始位置) cudaFree(m_GPU数据.m_cu刚体初始位置);

	m_GPU数据.m_cu位置 = nullptr;
	m_GPU数据.m_cu前一帧位置 = nullptr;
	m_GPU数据.m_cu速度 = nullptr;
	m_GPU数据.m_cu加速度 = nullptr;
	m_GPU数据.m_cu移动变化量 = nullptr;
	m_GPU数据.m_cu质量 = nullptr;
	m_GPU数据.m_cu平方范数 = nullptr;
	m_GPU数据.m_cu物理体类型 = nullptr;
	
}

/*float32 S_PDB数据::f_光滑内核(const vec3& p) {
	float32 光滑系数 = 1.0;

	const float32 距离 = vec_len(p);
	const float32 q = 距离 / m_粒子半径;

	if (q <= 0.5) {
		const float32 q2 = q * q;
		const float32 q3 = q2 * q;

		光滑系数 = m_内核因子 * (6.0 * q3 - 6.0 * q2 + 1.0);
	} else {
		光滑系数 = m_内核因子 * (2.0*pow(1.0-q, 3));
	}

	return 光滑系数;
}*/

vec3 S_PDB数据::f_梯度内核(const vec3& p) {
	vec3 梯度 = {};

	const float32 距离 = vec_len(p);
	const float32 q = 距离 / m_粒子光滑半径;

	if (距离 > 1.0e-6) {
		const vec3 梯度q = p * (1.0 / (距离 * m_粒子光滑半径));
		if (q <= 0.5) {
			梯度 = 梯度q * (m_粒子光滑半径 * q * (3.0 * q - 2.0));
		} else {
			const float32 factor = 1.0 - q;
			梯度 = 梯度q * (m_粒子光滑半径 * (-factor * factor));
		}
	}

	return 梯度;
}


void S_PDB数据::f_动态粒子重置(uint64 num) {
	m_位置.resize(num);
	m_速度.resize(num);
	m_质量.resize(num);


	m_上一帧位置.resize(num);
	m_物理体类型.resize(num);
	//m_动态邻接数量.resize(num);
	m_位置量变化.resize(num);
	m_密度.resize(num);
	//m_动态邻接粒子索引.resize(num);
	//m_方向.resize(num);
	m_流体粒子总数 = num;
}

void S_PDB数据::f_静态粒子重置(uint64 num) {
	//m_固定粒子.resize(num);
	//m_固定粒子磅力.resize(num);

	//m_静态粒子总数 = num;
}












void S_PDB数据::f_resize(uint64 num, bool 是否分配GPU) {
	if (m_位置.size() < num) {
		m_位置.resize(num);

		m_质量.resize(num);
		m_密度.resize(num);

		m_外力.resize(num);
		m_速度.resize(num);
		m_加速度.resize(num);
		m_Lambda.resize(num);


		m_上一帧位置.resize(num);
		m_位置量变化.resize(num);
		m_物理体类型.resize(num);
		m_物理体ID.resize(num);


		m_GPU数据.m_cu刚体起始索引 = nullptr;
		m_GPU数据.m_cu刚体粒子数量 = nullptr;
		m_GPU数据.m_cu刚体初始位置 = nullptr;

		if (是否分配GPU) {
			/*COUDA_CALL(cudaMalloc((void**)&(m_GPU数据.m_cu位置), sizeof(vec3) * num));
			COUDA_CALL(cudaMalloc((void**)&(m_GPU数据.m_cu前一帧位置), sizeof(vec3) * num));
			COUDA_CALL(cudaMalloc((void**)&(m_GPU数据.m_cu速度), sizeof(vec3) * num));
			COUDA_CALL(cudaMalloc((void**)&(m_GPU数据.m_cu加速度), sizeof(vec3) * num));
			COUDA_CALL(cudaMalloc((void**)&(m_GPU数据.m_cu移动变化量), sizeof(vec3) * num));
			COUDA_CALL(cudaMalloc((void**)&(m_GPU数据.m_cu外力), sizeof(vec3) * num));

			COUDA_CALL(cudaMalloc((void**)&(m_GPU数据.m_cu质量), sizeof(float32) * num));
			COUDA_CALL(cudaMalloc((void**)&(m_GPU数据.m_cu密度), sizeof(float32) * num));
			COUDA_CALL(cudaMalloc((void**)&(m_GPU数据.m_cu平方范数), sizeof(float32) * num));
			COUDA_CALL(cudaMalloc((void**)&(m_GPU数据.m_cu拉格朗日), sizeof(float32) * num));

			COUDA_CALL(cudaMalloc((void**)&(m_GPU数据.m_cu物理体ID), sizeof(uint32) * num));
			COUDA_CALL(cudaMalloc((void**)&(m_GPU数据.m_cu物理体类型), sizeof(uint8) * num));*/
		}
		
	}
	
}

void S_PDB数据::f_初始数据到GPU() {
	uint64 num = m_位置.size();

	//cudaMemcpy(m_GPU数据.m_cu位置, m_位置.data(), num * sizeof(vec3), cudaMemcpyKind::cudaMemcpyHostToDevice);
	//cudaMemcpy(m_GPU数据.m_cu质量, m_质量.data(), num * sizeof(float32), cudaMemcpyKind::cudaMemcpyHostToDevice);
	//cudaMemcpy(m_GPU数据.m_cu物理体ID, m_物理体ID.data(), num * sizeof(uint32), cudaMemcpyKind::cudaMemcpyHostToDevice);
	//cudaMemcpy(m_GPU数据.m_cu物理体类型, m_物理体类型.data(), num * sizeof(uint8), cudaMemcpyKind::cudaMemcpyHostToDevice);

	//cudaMemcpy(m_GPU数据.m_cu速度, m_速度.data(), num * sizeof(vec3), cudaMemcpyKind::cudaMemcpyHostToDevice);
	//cudaMemcpy(m_GPU数据.m_cu速度, m_速度.data(), num * sizeof(vec3), cudaMemcpyKind::cudaMemcpyHostToDevice);
	//cudaMemcpy(m_GPU数据.m_cu前一帧位置, m_位置.data(), num * sizeof(vec3), cudaMemcpyKind::cudaMemcpyHostToDevice);
	//cudaMemcpy(m_GPU数据.m_cu移动变化量, m_位置量变化.data(), num * sizeof(vec3), cudaMemcpyKind::cudaMemcpyHostToDevice);
	//cudaMemcpy(m_GPU数据.m_cu外力, m_位置量变化.data(), num * sizeof(vec3), cudaMemcpyKind::cudaMemcpyHostToDevice);
}

void S_PDB数据::f_数据到GPU() {
	uint64 num = m_位置.size();


	//cudaDeviceSynchronize();

	//cudaMemcpy(m_GPU数据.m_cu位置, m_位置.data(), num * sizeof(vec3), cudaMemcpyKind::cudaMemcpyHostToDevice);
	//cudaMemcpy(m_GPU数据.m_cu密度, m_质量.data(), num * sizeof(float32), cudaMemcpyKind::cudaMemcpyHostToDevice);
	//cudaMemcpy(m_GPU数据.m_cu质量, m_质量.data(), num * sizeof(float32), cudaMemcpyKind::cudaMemcpyHostToDevice);
}

void S_PDB数据::f_数据到CPU() {
	uint64 num = m_位置.size();
	//std::cout << "1:" << num << std::endl;
	//cudaMemcpy(m_位置.data(), m_GPU数据.m_cu位置, num * sizeof(vec3), cudaMemcpyKind::cudaMemcpyDeviceToHost);
	//std::cout << "2" << std::endl;
	//cudaMemcpy(m_上一帧位置.data(), m_GPU数据.m_cu前一帧位置, num * sizeof(vec3), cudaMemcpyKind::cudaMemcpyDeviceToHost);
	return;
	//std::cout << "3" << std::endl;
	//cudaMemcpy(m_速度.data(), m_GPU数据.m_cu速度, num * sizeof(vec3), cudaMemcpyKind::cudaMemcpyDeviceToHost);
	//std::cout << "4" << std::endl;
	//cudaMemcpy(m_加速度.data(), m_GPU数据.m_cu加速度, num * sizeof(vec3), cudaMemcpyKind::cudaMemcpyDeviceToHost);
	//std::cout << "5" << std::endl;
	//cudaMemcpy(m_位置量变化.data(), m_GPU数据.m_cu移动变化量, num * sizeof(vec3), cudaMemcpyKind::cudaMemcpyDeviceToHost);
	std::cout << "6" << std::endl;
	//cudaMemcpy(m_质量.data(), m_GPU数据.m_cu质量, num * sizeof(float32), cudaMemcpyKind::cudaMemcpyDeviceToHost);
	uint32 块复制数量 = m_流体粒子总数 / (m_GPU数据.m_线程块大小 * 10);
#pragma omp parallel for
	for (int32 i = 0; i < 块复制数量; ++i) {
		uint64 offset = m_GPU数据.m_线程块大小 * 10 * i;
		//cudaMemcpy(&(m_位置[offset]), &(m_GPU数据.m_cu位置[offset]), m_GPU数据.m_线程块大小 * 10 * sizeof(vec3), cudaMemcpyKind::cudaMemcpyDeviceToHost);
		//cudaMemcpy(&(m_上一帧位置[offset]), &(m_GPU数据.m_cu前一帧位置[offset]), m_GPU数据.m_线程块大小 * 10 * sizeof(vec3), cudaMemcpyKind::cudaMemcpyDeviceToHost);
	}

	
	uint64 offset = 块复制数量 * m_GPU数据.m_线程块大小 * 10;
	num = m_流体粒子总数 - offset;
	if (num) {
		//cudaMemcpy(&m_位置[offset], &(m_GPU数据.m_cu位置[offset]), num * sizeof(vec3), cudaMemcpyKind::cudaMemcpyDeviceToHost);
		//cudaMemcpy(&m_上一帧位置[offset], &(m_GPU数据.m_cu前一帧位置[offset]), num * sizeof(vec3), cudaMemcpyKind::cudaMemcpyDeviceToHost);
	}
	
	//cudaMemcpyAsync(m_位置.data(), m_GPU数据.m_cu位置, num * sizeof(vec3), cudaMemcpyKind::cudaMemcpyDeviceToHost, stm);
	//cudaMemcpyAsync(m_上一帧位置.data(), m_GPU数据.m_cu前一帧位置, num * sizeof(vec3), cudaMemcpyKind::cudaMemcpyDeviceToHost, stm);

}

uint64 S_PDB数据::f_size() {
	return m_位置.size();
}


